package com.yhd.rabbit.config;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * 说明：该配置类用于事务消息和confirm模式的测试
 * 在测试延迟消息的时候，需要注释掉。
 * @author yhd
 * @createtime 2021/1/23 1:38
 * @description 消息发送确认
 *  关于实现的这两个类：
 *      ConfirmCallback：只确认消息是否正确到达Exchange中
 *          1.如果消息没有到exchange,则confirm回调,ack=false
 *          2.如果消息到达exchange,则confirm回调,ack=true
 *      ReturnCallback：消息没有正确到达队列时触发回调，如果正确到达队列不执行
 *          1.exchange到queue成功,则不回调return
 *          2.exchange到queue失败,则回调return
 */
@Slf4j
//@SpringBootConfiguration
public class MQProducerAckConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback{

    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 修饰一个非静态的void（）方法,在服务器加载Servlet的时候运行，
     * 并且只会被服务器执行一次。
     * 在构造函数之后执行，init（）方法之前执行。
     */
    @PostConstruct
    public void init() {

        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnCallback(this);

    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("消息发送成功：" + JSONUtil.toJsonStr(correlationData));
        } else {
            System.out.println("消息发送失败：" + cause + " 数据：" + JSONUtil.toJsonStr(correlationData));
        }
    }

    /**
     * 如果消息未从路由成功发送到队列那么会走这个回调，这里会把消息的整个明细返回
     * 也就是说出错了，才会调用哦。
     */
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        // 反序列化对象输出
        System.out.println("消息主体: {}"+new String(message.getBody()));
        System.out.println("应答码: {}"+replyCode);
        System.out.println("描述：{}"+replyText);
        System.out.println("消息使用的交换器 exchange : {}"+exchange);
        System.out.println("消息使用的路由键 routing : {}"+routingKey);
    }
}